package com.hengxinyongli.iam.web.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.hengxinyongli.iam.anotation.NoAuth;
import com.hengxinyongli.iam.anotation.ValidateToken;
import com.hengxinyongli.iam.dto.Subject;
import com.hengxinyongli.iam.entity.Resource;
import com.hengxinyongli.iam.entity.User;
import com.hengxinyongli.iam.jwt.JwtAuthService;
import com.hengxinyongli.iam.service.ResourceService;
import com.hengxinyongli.iam.service.UserService;
import com.hengxinyongli.iam.utils.AssertUtils;
import com.hengxinyongli.iam.utils.VerifyCode;
import com.hengxinyongli.iam.web.constant.Res;
import com.hengxinyongli.iam.web.constant.Url;
import com.hengxinyongli.iam.web.vo.Responses;
import com.hengxinyongli.smscenter.enums.MessageChannel;
import com.hengxinyongli.smscenter.service.MessageService;
import io.swagger.annotations.*;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 * @author magic
 * @date 2018/9/25/025 13:32
 * @version 1.0
 * Description UserController
 */
@RestController
@Api(description = "用户相关api")
public class UserController {

    private Logger logger = LoggerFactory.getLogger(UserController.class);

    public static final String VERIFY_CODE_PREFIX = "USER_VERIFY_CODE_";

    @Autowired
    UserService userService;

    @Autowired
    ResourceService resourceService;

    @Autowired
    JwtAuthService jwtAuthService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Reference(check = false,timeout = 6000,cluster = "failfast",version = "1.0.0")
    MessageService messageService;

    @Value("${login.day.max:5}")
    private Long maxLoginCount;

    @GetMapping(Url.USERS)
    @ApiOperation(value = "获取所有用户列表",notes = "获取所有用户列表")
    public Responses users(@RequestParam(required = false) @ApiParam(value = "分页查询页号码") Integer pageNo,
                           @RequestParam(required = false) @ApiParam(value = "分页查询页大小") Integer pageSize,
                           @RequestParam(required = false) @ApiParam(value = "模糊查询用户名") String userName,
                           @RequestParam(required = false) @ApiParam(value = "用户状态") String status,
                           @RequestParam(required = false) @ApiParam(value = "手机号码") String mobile){
        PageInfo<User> users = userService.selectAllUsers(pageNo,pageSize,userName,status,mobile);
        return Responses.success(users);
    }

    @GetMapping(Url.USERS_ONE)
    @ApiOperation(value = "获取指定用户的信息",notes = "获取指定用户的信息")
    @ApiResponses(
            @ApiResponse(code = 200,message = "操作成功",response = UserInfo.class)
    )
    public Responses usersOne(@PathVariable @ApiParam(value = "用户编号") Long id, @RequestParam(required = false) String type){
        User user = userService.selectUserById(id);
        AssertUtils.isTrue(Objects.nonNull(user),"用户不存在.");
        if(StringUtils.isNotEmpty(type)){
            UserInfo userInfo = resourceService.selectUserInfoResourcesByType(user,type);
            return Responses.success(userInfo);
        }
        return Responses.success(user);
    }

    @GetMapping(Url.USER_INFO)
    @ValidateToken
    @ApiOperation(value = "获取当前登录的用户信息",notes = "获取当前登录的用户信息")
    @ApiResponses(
            @ApiResponse(code = 200,message = "操作成功",response = UserInfo.class)
    )
    public Responses userInfo(@ApiIgnore @RequestAttribute Subject subject){
        User user = userService.selectUserById(subject.getUserId());
        UserInfo userInfo = resourceService.selectUserInfoResourcesByType(user,Res.ALL);
        return Responses.success(userInfo);
    }

    @PostMapping(Url.USERS)
    @ApiOperation(value = "创建新用户",notes = "创建新用户")
    @ApiResponses(
            @ApiResponse(code = 200,message = "操作成功",response = User.class)
    )
    public Responses usersCreate(@Validated  @RequestBody UserRo userRo){
        User user = new User();
        BeanUtils.copyProperties(userRo,user);
        userService.usersCreate(user,userRo.getUserRoles());
        return Responses.success(user);
    }


    @PutMapping(Url.USERS_ONE)
    @ApiOperation(value = "修改指定ID的用户信息",notes = "修改指定ID的用户信息")
    @ApiResponses(
            @ApiResponse(code = 200,message = "操作成功",response = User.class)
    )
    public Responses userUpdate(@PathVariable @ApiParam(value = "用户编号") Long id,@RequestBody UserRoUpdate userRo){
        User user = userService.usersUpdate(id,userRo);
        return Responses.success(user);
    }

    @PutMapping(Url.USER_RESET_PWD)
    @ApiOperation(value = "用户修改密码",notes = "用户修改密码")
    @ApiResponses(
            @ApiResponse(code = 200,message = "操作成功",response = User.class)
    )
    @ValidateToken
    public Responses userReset(@ApiIgnore @RequestAttribute Subject subject,@RequestBody UserResetPwd resetPwd){
        User user = userService.userReset(subject,resetPwd.getOrigin(),resetPwd.getNewer());
        return Responses.success(user);
    }

    @DeleteMapping(Url.USERS_ONE)
    @ApiOperation(value = "删除指定ID的用户信息",notes = "删除指定ID的用户信息")
    @ApiResponses(
            @ApiResponse(code = 200,message = "操作成功")
    )
    public Responses userDelete(@PathVariable @ApiParam(value = "用户编号") Long id){
        userService.usersDelete(id);
        return Responses.success(id);
    }

    @GetMapping(Url.SMS_CODE)
    @NoAuth
    @ApiOperation(value = "获取短信验证码",notes = "获取短信验证码")
    public Responses smsMessageCode(@RequestParam @ApiParam(value = "手机号码") String mobile){
        String randNumber = RandomStringUtils.random(6,false,true);
        logger.info("smsMessageCode: get sms code: {}, mobile: {}",randNumber,mobile);
        User user = userService.getLoginUser(mobile);
        Long count = stringRedisTemplate.opsForValue().increment(Res.SMS_LOGIN_COUNT_PREFIX.concat(user.getMobile()),0);
        AssertUtils.isTrue(count <= maxLoginCount,"您当日获取短信验证码次数过多，请使用账号密码登录!");
        Boolean sendStatus = messageService.sendMessage(mobile,"您正在登录特快管理后台，5分钟内有效,您的登录短信验证码为: " + randNumber, MessageChannel.DIAN_JI);
        AssertUtils.isTrue(sendStatus,"短信验证码发送失败，请联系管理员!");
        Long incCount = stringRedisTemplate.opsForValue().increment(Res.SMS_LOGIN_COUNT_PREFIX.concat(user.getMobile()),1);
        stringRedisTemplate.opsForValue().set(Res.SMS_LOGIN_PREFIX.concat(user.getMobile()),randNumber,5, TimeUnit.MINUTES);
        return Responses.success(incCount);
    }

    @GetMapping(Url.VERIFY_CODE)
    @NoAuth
    @ApiOperation(value = "获取验证码",notes = "获取验证码")
    public void verifyCode(@RequestParam @ApiParam(value = "手机号码") String mobile,@ApiIgnore HttpServletResponse response){
        response.setContentType(MediaType.IMAGE_JPEG_VALUE);
        response.setHeader(HttpHeaders.PRAGMA, VerifyCode.NO_CACHE);
        response.setHeader(HttpHeaders.CACHE_CONTROL, VerifyCode.NO_CACHE);
        response.setDateHeader(HttpHeaders.EXPIRES, VerifyCode.EXPIRES_DATE);
        VerifyCode vCode = new VerifyCode(
                VerifyCode.VERIFY_CODE_WIDTH,
                VerifyCode.VERIFY_CODE_HEIGHT,
                VerifyCode.VERIFY_CODE_COUNT,
                VerifyCode.VERIFY_CODE_LINE_COUNT
        );
        logger.info("verifyCode: {}, mobile: {}",vCode.getCode(),mobile);
        stringRedisTemplate.opsForValue().set(VERIFY_CODE_PREFIX.concat(mobile),vCode.getCode().toLowerCase());
        try {
            vCode.write(response.getOutputStream());
        } catch (IOException e) {
            logger.error("get verifyCode exception: {}", ExceptionUtils.getRootCauseMessage(e));
        }
    }

    @PostMapping(Url.USER_LOGIN)
    @NoAuth
    @ApiOperation(value = "用户登录",notes = "用户登录")
    @ApiResponses(
            @ApiResponse(code = 200,message = "操作成功",response = UserLoginResp.class)
    )
    public Responses userLogin(@Validated @RequestBody UserLogin userLogin){
        logger.info("userLogin request: {}", JSON.toJSONString(userLogin));
        User loginUser = userService.getLoginUser(userLogin.getMobile());
        AssertUtils.isTrue(Res.UN_FREEZE_STATUS.equals(loginUser.getStatus()),"当前用户已被冻结，请联系管理员！.");
        String verifyCode = stringRedisTemplate.opsForValue().get(VERIFY_CODE_PREFIX.concat(loginUser.getMobile()));
        AssertUtils.isTrue(StringUtils.isNotEmpty(verifyCode),"没有获取图形验证码,请先获取验证码");
        AssertUtils.isTrue(userLogin.verifyCode.toLowerCase().equals(verifyCode),"验证码校验失败.");
        Subject subject = userService.userLogin(userLogin.getMobile(),userLogin.getPassword(),userLogin.getLoginType(),loginUser);
        String userToken = jwtAuthService.createJwtToken(subject);
        UserLoginResp loginResp = new UserLoginResp(userToken,subject.getMobile(),subject.getUserId(),subject.getUserName());
        return Responses.success(loginResp);
    }

    @ApiModel
    public static class UserInfo implements Serializable {

        @ApiModelProperty(value = "用户基础信息")
        private User userBase;
        @ApiModelProperty(value = "用户菜单资源信息")
        private List<Resource> menus;
        @ApiModelProperty(value = "用户按钮资源信息")
        private List<Resource> btns;
        @ApiModelProperty(value = "用户角色信息")
        private List<String> roles;
        @ApiModelProperty(value = "是否管理员")
        private Boolean isAdmin;

        public User getUserBase() {
            return userBase;
        }

        public void setUserBase(User userBase) {
            this.userBase = userBase;
        }

        public List<Resource> getMenus() {
            return menus;
        }

        public void setMenus(List<Resource> menus) {
            this.menus = menus;
        }

        public List<Resource> getBtns() {
            return btns;
        }

        public void setBtns(List<Resource> btns) {
            this.btns = btns;
        }

        public Boolean getAdmin() {
            return isAdmin;
        }

        public void setAdmin(Boolean admin) {
            isAdmin = admin;
        }

        public List<String> getRoles() {
            return roles;
        }

        public void setRoles(List<String> roles) {
            this.roles = roles;
        }
    }

    @ApiModel
    public static class UserLoginResp {
        @ApiModelProperty(value = "用户TOKEN")
        private String token;
        @ApiModelProperty(value = "手机号")
        private String mobile;
        @ApiModelProperty(value = "用户编号")
        private Long userId;
        @ApiModelProperty(value = "用户名称")
        private String userName;

        public UserLoginResp(String token, String mobile, Long userId, String userName) {
            this.token = token;
            this.mobile = mobile;
            this.userId = userId;
            this.userName = userName;
        }

        public String getMobile() {
            return mobile;
        }

        public void setMobile(String mobile) {
            this.mobile = mobile;
        }

        public String getToken() {
            return token;
        }

        public void setToken(String token) {
            this.token = token;
        }

        public Long getUserId() {
            return userId;
        }

        public void setUserId(Long userId) {
            this.userId = userId;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }
    }


    @ApiModel
    public static class UserLogin {
        @ApiModelProperty(value = "手机号")
        @NotEmpty(message = "用户手机号不能为空")
        private String mobile;
        @ApiModelProperty(value = "密码")
        @NotEmpty(message = "密码不能为空")
        private String password;
        @ApiModelProperty(value = "验证码")
        @NotEmpty(message = "验证码不能为空")
        private String verifyCode;

        @ApiModelProperty(value = "登录方式，不传为密码登录，传入值则使用短信验证码登录")
        private Integer loginType;

        public Integer getLoginType() {
            return loginType;
        }

        public void setLoginType(Integer loginType) {
            this.loginType = loginType;
        }

        public String getMobile() {
            return mobile;
        }

        public void setMobile(String mobile) {
            this.mobile = mobile;
        }

        public String getVerifyCode() {
            return verifyCode;
        }

        public void setVerifyCode(String verifyCode) {
            this.verifyCode = verifyCode;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    @ApiModel(value = "创建用户")
    public static class UserRo {

        @ApiModelProperty(value = "用户名称")
        @NotEmpty(message = "用户名称不能为空")
        private String userName;

        @ApiModelProperty(value = "用户类型")
        @NotEmpty(message = "用户类型不能为空")
        private String userType;

        @ApiModelProperty(value = "手机号")
        @NotEmpty(message = "用户手机号不能为空")
        private String mobile;

        @ApiModelProperty(value = "登录密码")
        @NotEmpty(message = "登录密码不能为空")
        private String password;

        @ApiModelProperty(value = "状态")
        @NotEmpty(message = "用户状态不能为空")
        private String status;

        @ApiModelProperty(value = "部门")
        @NotEmpty(message = "用户部门不能为空")
        private String depId;

        @ApiModelProperty(value = "角色列表")
        @NotEmpty(message = "用户角色列表不能为空")
        private Set<String> userRoles;

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public String getUserType() {
            return userType;
        }

        public void setUserType(String userType) {
            this.userType = userType;
        }

        public String getMobile() {
            return mobile;
        }

        public void setMobile(String mobile) {
            this.mobile = mobile;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public String getDepId() {
            return depId;
        }

        public void setDepId(String depId) {
            this.depId = depId;
        }

        public Set<String> getUserRoles() {
            return userRoles;
        }

        public void setUserRoles(Set<String> userRoles) {
            this.userRoles = userRoles;
        }
    }

    @ApiModel(value = "用户修改密码")
    public static class UserResetPwd {
        @ApiModelProperty(value = "原密码")
        @NotEmpty(message = "原密码不能为空")
        private String origin;
        @ApiModelProperty(value = "新密码")
        @NotEmpty(message = "新密码不能为空")
        private String newer;

        public String getOrigin() {
            return origin;
        }

        public void setOrigin(String origin) {
            this.origin = origin;
        }

        public String getNewer() {
            return newer;
        }

        public void setNewer(String newer) {
            this.newer = newer;
        }
    }

    @ApiModel(value = "修改用户信息")
    public static class UserRoUpdate {

        @ApiModelProperty(value = "用户名称")
        @NotEmpty(message = "用户名称不能为空")
        private String userName;

        @ApiModelProperty(value = "用户类型")
        private String userType;

        @ApiModelProperty(value = "登录密码")
        private String password;

        @ApiModelProperty(value = "状态")
        private String status;

        @ApiModelProperty(value = "部门")
        private String depId;

        @ApiModelProperty(value = "角色列表")
        private Set<String> userRoles;

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public String getUserType() {
            return userType;
        }

        public void setUserType(String userType) {
            this.userType = userType;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public String getDepId() {
            return depId;
        }

        public void setDepId(String depId) {
            this.depId = depId;
        }

        public Set<String> getUserRoles() {
            return userRoles;
        }

        public void setUserRoles(Set<String> userRoles) {
            this.userRoles = userRoles;
        }
    }
}
